package com.uniandes.modelviewer.converter;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.impl.DynamicEObjectImpl;
import org.eclipse.emf.ecore.impl.EAttributeImpl;
import org.eclipse.emf.ecore.impl.EReferenceImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import com.uniandes.modelviewer.Attribute;
import com.uniandes.modelviewer.Class;
import com.uniandes.modelviewer.Model;
import com.uniandes.modelviewer.Relation;
import com.uniandes.modelviewer.dsl.EcoreMetaModel;
import com.uniandes.modelviewer.dsl.XmiModel;


public class ModelReader {
	
	
	private String metamodelUri;
	private String modelUri;
	private ArrayList<Attribute> attributes;
	private ArrayList<com.uniandes.modelviewer.Class> classes;
	private ArrayList<Relation> relations;
	private Model model;
	private XmiModel xmiModel;
	private EcoreMetaModel metaModel;

	public void setMetamodelUri(String metamodelUri) {
		this.metamodelUri = metamodelUri;
	}

	public void setModelUri(String modelUri) {
		this.modelUri = modelUri;
	}

	/**
	 * PRE - Se ha ejecutado correctamente el metodo setMetamodelUri correctamente
	 * @return
	 */
	public void darMetamodeloEnDSL()
	{
		String rta = "";

		ResourceSet metaResourceSet = new ResourceSetImpl();
		metaResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl());
		Resource metaResource = metaResourceSet.getResource(URI.createFileURI(metamodelUri), true);
		EPackage metaPackage = (EPackage) metaResource.getContents().get(0);		

		rta += "Diagram myDiagram +dynamic {\n";
		EList<EClassifier> list = metaPackage.getEClassifiers();
		EReferenceImpl ref;
		EAttributeImpl attr;
		Iterator<EClassifier> it = list.iterator();
		String association = "";
		while(it.hasNext())
		{
			EClassifier classifier = it.next();
			String name = classifier.getName();			
			rta += "class "+name+"\n {\n";
			Iterator<EObject> contents = classifier.eContents().iterator();
			while(contents.hasNext())
			{
				EObject obj = contents.next();				
				if(obj.getClass().equals(EAttributeImpl.class))
				{
					attr = (EAttributeImpl)obj;
					rta += "Attribute "+attr.getName()+ " : "+ attr.getEType().getName()+ ";\n";
				}
			}
			rta += "}\n";
			
			contents = classifier.eContents().iterator();
			while(contents.hasNext())
			{
				EObject obj = contents.next();
				if(obj.getClass().equals(EReferenceImpl.class))
				{
					ref = (EReferenceImpl)obj;
					association+= "association ";
					association+= ref.getName();
					association+=" {\n role _"+ref.getLowerBound() + " : " + name+";";
					association+=" \n role _"+ref.getUpperBound() + " : " + ref.getEType().getName()+" +navigable;\n}\n";
				}
			}		
		}
		rta += association;
		rta += "}";
		File x = new File(metamodelUri);
		metaModel = new EcoreMetaModel();
		String[] campos = x.getName().split("\\."); 
		String fileName = campos[0];
		metaModel.setName(fileName);
		metaModel.setModelDsl(rta);
		campos = null;
		fileName = null;
		rta = null;
		x = null;
		System.gc();
	}
	
	/**
	 * PRE - Se ha ejecutado correctamente el metodo setMetamodelUri y setModelUri correctamente
	 * @return
	 */
	public void darModeloEnDSL()
	{
		String rta = "";

		ResourceSet metaResourceSet = new ResourceSetImpl();
		metaResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl());
		Resource metaResource = metaResourceSet.getResource(URI.createFileURI(metamodelUri), true);
		EPackage metaPackage = (EPackage) metaResource.getContents().get(0);

		ResourceSet xmiResourceSet = new ResourceSetImpl();
		xmiResourceSet.getPackageRegistry().put(metaPackage.getNsURI(), metaPackage);
		xmiResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl());
		Resource xmiResource = xmiResourceSet.getResource(URI.createFileURI(modelUri), true);

		rta += "Diagram myDiagram +dynamic {\n";
		TreeIterator<EObject> iterator = xmiResource.getAllContents();
		String association = "";

		while (iterator.hasNext()) {

			EObject classObject = iterator.next();
			String name ="";
			name = darNuevoNombreClase(classObject);
			rta += "class "+name+"\n {\n";
			//Attributes
			for (EStructuralFeature attribute : classObject.eClass().getEAllAttributes()) {
				if(!attribute.getName().equals("id")){
					Object attributeObject = classObject.eGet(attribute);
					rta += "Attribute "+attribute.getName()+ " : _"+ attributeObject.toString()+ ";\n";
				}
			}
			rta += "}\n";

			//References
			for (EStructuralFeature reference : classObject.eClass().getEAllReferences()) {
				Object referenceObject = classObject.eGet(reference);				
				if(referenceObject.getClass().equals(DynamicEObjectImpl.class)){
					String endpointName = darNuevoNombreClase((EObject)referenceObject);
					association+= "association ";
					association+= endpointName.toLowerCase()+name.toLowerCase();
					association+=" {\n role _" + " : " + name + ";";
					association+=" \n role "+reference.getName() + " : " + endpointName+" +navigable;\n}\n";				
				}

				else if(referenceObject.getClass().getName().endsWith("EcoreEList$Dynamic")){
					for(Object object : (EList<EObject>)referenceObject){
						String endpointName = darNuevoNombreClase((EObject)object);
						association+= "association ";
						association+= endpointName.toLowerCase()+name.toLowerCase();
						association+=" {\n role _" + " : " + name+";";
						association+=" \n role "+endpointName.toLowerCase() + " : " + endpointName+" +navigable;\n}\n";
					}
				}		
			}
		}
		rta += association;
		rta += "}";
		File x = new File(modelUri);
		xmiModel = new XmiModel();
//		String[] campos = x.getName().split("\\."); 
//		String fileName = campos[0];
		xmiModel.setName(x.getName());
		xmiModel.setModelDsl(rta);
//		campos = null;
//		fileName = null;
		rta = null;
		x = null;
		System.gc();
	}

	private String darNuevoNombreClase(EObject objetoI) {
		String nomClase = objetoI.eClass().getName();
		for (EStructuralFeature attribute : objetoI.eClass().getEAllAttributes()) {
			if(attribute.getName().equals("id"))
			{
				Object attributeObject = objetoI.eGet(attribute);
				nomClase += attributeObject.toString();
			}
		}

		return nomClase;
	}
	
	public void saveModel()
	{
		attributes = new ArrayList<Attribute>();
		classes = new ArrayList<com.uniandes.modelviewer.Class>();
		relations = new ArrayList<Relation>();
		model = new Model();

		ResourceSet metaResourceSet = new ResourceSetImpl();
		metaResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl());
		Resource metaResource = metaResourceSet.getResource(URI.createFileURI(metamodelUri), true);
		EPackage metaPackage = (EPackage) metaResource.getContents().get(0);

		ResourceSet xmiResourceSet = new ResourceSetImpl();
		xmiResourceSet.getPackageRegistry().put(metaPackage.getNsURI(), metaPackage);
		xmiResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl());
		Resource xmiResource = xmiResourceSet.getResource(URI.createFileURI(modelUri), true);

		TreeIterator<EObject> iterator = xmiResource.getAllContents();
		com.uniandes.modelviewer.Class mClass;
		com.uniandes.modelviewer.Class mClass2;
		Attribute a;
		//Guardando Clases y Atributos.
		while (iterator.hasNext()) {
			mClass = new Class();
			EObject classObject = iterator.next();
			String name ="";
			name = darNuevoNombreClase(classObject);
			mClass.setName(name);
			//Attributes
			
			for (EStructuralFeature attribute : classObject.eClass().getEAllAttributes()) {
				if(!attribute.getName().equals("id")){
					Object attributeObject = classObject.eGet(attribute);
					a = new Attribute();
					a.setName(attribute.getName());
					a.setValue(attributeObject.toString());
					a.setType("");
					attributes.add(a);
					a = null;
				}
			}
			
			mClass.setAttributes(attributes);
			
			classes.add(mClass);
			attributes = new ArrayList<Attribute>();
			mClass = null;
			a = null;
			System.gc();			
		}
		iterator = xmiResource.getAllContents();
		//Guardando relaciones.
		while(iterator.hasNext())
		{
			EObject classObject = iterator.next();
			String name ="";
			name = darNuevoNombreClase(classObject);
			mClass = getClassFromName(classes, name);
			Relation rel;
			//References
			for (EStructuralFeature reference : classObject.eClass().getEAllReferences()) {
				Object referenceObject = classObject.eGet(reference);				
				if(referenceObject.getClass().equals(DynamicEObjectImpl.class)){
					String endpointName = darNuevoNombreClase((EObject)referenceObject).toLowerCase();
					endpointName = endpointName.toLowerCase().toLowerCase();
					System.out.println(endpointName);
					mClass2 = getClassFromName(classes, endpointName);					
					rel = new Relation();
					rel.setName(endpointName+name.toLowerCase());
					rel.setFrom(mClass);
					rel.setTo(mClass2);
					relations.add(rel);
					rel = null;
				}

				else if(referenceObject.getClass().getName().endsWith("EcoreEList$Dynamic")){
					for(Object object : (EList<EObject>)referenceObject){
						String endpointName = darNuevoNombreClase((EObject)object);
						endpointName = endpointName.toLowerCase().toLowerCase();
						System.out.println(endpointName);
						mClass2 = getClassFromName(classes, endpointName);
						rel = new Relation();
						rel.setName(endpointName+name.toLowerCase());
						rel.setFrom(mClass);
						rel.setTo(mClass2);
						relations.add(rel);
						rel = null;
					}
				}		
			}
		}
		File x = new File(modelUri);
		model.setName(x.getName());
		model.setClasses(classes);
		model.setRelations(relations);
		x = null;
	}
	
	private Class getClassFromName(ArrayList<Class> classes, String name)
	{
		Class c = null;
		for(int i = 0; i < classes.size(); i++)
		{
			c = classes.get(i);
			if(c.getName().equalsIgnoreCase(name))
			{
				return c;				
			}
		}
		return null;
	}

	/**
	 * @return the attributes
	 */
	public ArrayList<Attribute> getAttributes() {
		return attributes;
	}

	/**
	 * @return the classes
	 */
	public ArrayList<com.uniandes.modelviewer.Class> getClasses() {
		return classes;
	}

	/**
	 * @return the relations
	 */
	public ArrayList<Relation> getRelations() {
		return relations;
	}

	/**
	 * @return the model
	 */
	public Model getModel() {
		return model;
	}

	/**
	 * @return the xmiModel
	 */
	public XmiModel getXmiModel() {
		return xmiModel;
	}

	/**
	 * @return the metaModel
	 */
	public EcoreMetaModel getMetaModel() {
		return metaModel;
	}
	
	
	
	
	
}
